package simorg.view;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import simorg.actions.Action;
import simorg.controller.AdminController;
import simorg.controller.AppController;
import simorg.controller.AssignmentController;
import simorg.controller.Controller;
import simorg.controller.CourseController;
import simorg.controller.UserController;
import simorg.util.Config;
import simorg.util.DatabaseConnection;

public class WebSessionContext {

	HttpServletRequest request;
	HttpServletResponse response;
	HttpServlet servlet;
	
	String controller;
	String actionName;
	String appSwitch;
	ArrayList<String> requestArgs;
	ViewOptions viewOptions;
	
	private static String adminRoot = "admin/";
	private static String appRoot = "app/"; 
	
	static HashMap<String, Controller> controllers = null;
	
	static {
		controllers = new HashMap<String, Controller>();
		controllers.put(AdminController.controllerName, new AdminController());
		controllers.put(UserController.controllerName, new UserController());
		controllers.put(CourseController.controllerName, new CourseController());
		controllers.put(AppController.controllerName, new AppController());
		controllers.put(AssignmentController.controllerName, new AssignmentController());
	}
			
		

	public WebSessionContext(HttpServlet dispatch, HttpServletRequest request, HttpServletResponse response) {
		this.request = request;
		this.response = response;
		this.servlet = dispatch;
		this.viewOptions = new ViewOptions();
		mapURL();
	}
	
	
	
	public ViewOptions getViewOptions() {
		return viewOptions;
	}



	private void mapURL() {
		String url = request.getRequestURL().toString();
		String [] rsa = null;
		if ( url.contains("simorg/" + adminRoot) ) {
			rsa = url.split("simorg/" + adminRoot);
			this.appSwitch = adminRoot;
		}
		else {
			rsa = url.split("simorg/" + appRoot);
			this.appSwitch = appRoot;
		}
		String restString = rsa.length < 2 ? "" : rsa[1];
		if ( url.indexOf("?") >= 0) {
			restString = url.split("?")[0];
		}
		if ( url.indexOf(";") >= 0) {
			restString = url.split(";")[0];
		}
		this.requestArgs = new ArrayList<String>();
		String [] fields = restString.split("/");
		controller = fields[0];
		for ( int i = 1; i < fields.length; i++ ){
			this.requestArgs.add(fields[i]);
		}
		
		System.out.println("Controller:  " + controller);
		if ( this.requestArgs.size() > 0 ) {
			actionName = this.requestArgs.get(0);
			this.requestArgs.remove(0);
			System.out.println("Action:  " + actionName);
		}
		else {
			actionName = "";
		}
		
		for ( String f : this.requestArgs ) {
			System.out.println("\tArg:  " + f);
		}
	}
	
	public DatabaseConnection getDbConnection() {
		Object odc = this.request.getSession().getAttribute(SessionAttribute.DatabaseConnection.getName());
		DatabaseConnection dc = null;
		if ( odc != null ) {
			dc = (DatabaseConnection) odc;
			if ( dc.isOpen() ) {
				return dc;
			}
		}
		try {
			dc = new DatabaseConnection();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			return null;
		} catch (SQLException e) {
			e.printStackTrace();
			return null;
		}
		request.getSession().setAttribute(SessionAttribute.DatabaseConnection.getName(), dc);
		return dc;
	}
	
	@SuppressWarnings("unchecked")
	public void addFlash(Flash flash) {
		Collection<Flash> flashList = null;
		if ( request.getSession().getAttribute(SessionAttribute.FlashList.getName()) != null ) {
			flashList = (Collection<Flash>) request.getSession().getAttribute(SessionAttribute.FlashList.getName());
		}
		if ( flashList == null ) {
			flashList = new ArrayList<Flash>();
			request.getSession().setAttribute(SessionAttribute.FlashList.getName(), flashList);
		}
		flashList.add(flash);
	}

	private ArrayList<String> getRequestArgs() {
		return requestArgs;
	}

	public HttpServlet getServlet() {
		return servlet;
	}

	public HttpServletRequest getRequest() {
		return request;
	}

	public HttpServletResponse getResponse() {
		return response;
	}
	
	public Action getAction() {
		Controller c = controllers.get(this.controller);
		if ( c == null ) {
			c = this.appSwitch.equalsIgnoreCase(adminRoot)? new AdminController() : new AppController();
		}
		
		Action action = c.getActionHandler(actionName) ;
		action.setRequestArgs(this.getRequestArgs());
		return action;
	}
	       
	
	public String getContextRootURL() {
		String scheme = this.request.getScheme();             // http
	    String serverName = this.request.getServerName();     // hostname.com
	    int serverPort = this.request.getServerPort();        // 80
	    String contextPath = this.request.getContextPath();   // /mywebapp
	    
	    String base = scheme + "://" + serverName + ":" + serverPort + contextPath;
	    return base;
	}
	public void redirectApp(Action a) throws Exception {
		redirect(appRoot, a, null);
	}
	public void redirectApp(Action a, String anchor) throws Exception {
		redirect(appRoot, a, anchor);
	}
	public void redirectAdmin(Action a) throws Exception {
		redirect(adminRoot, a, null);
	}
	public void redirectAdmin(Action a, String anchor) throws Exception {
		redirect(adminRoot, a, anchor);
	}
	public void redirect(String root, Action a, String anchor) throws Exception {
		String base = getContextRootURL() + "/" + root;
		try {
		    String redirect =  base + a.getControllerName() + "/" + a.getName() + "/";
		    if ( a.getRequestArgs() != null ) {
		    	for( String arg : a.getRequestArgs() ) {
		    		redirect += (arg + "/");
		    	}
		    }
		    if ( anchor != null ) redirect += ("#" + anchor);	
			System.out.println("Redirecting to " + redirect);
			this.getResponse().sendRedirect(redirect);
		}
		catch (Exception e) {
			this.getResponse().sendRedirect(base);
		}
	}
	
	@SuppressWarnings("unchecked")
	public Document buildBaseXml() {
		Document xmlDoc = DocumentHelper.createDocument();
		Element root = xmlDoc.addElement( "simorg" );
        root.addAttribute("version", Config.getVersionString());
        buildPathXml(root);
        // Add user information
        
        if ( request.getSession().getAttribute(SessionAttribute.FlashList.getName()) != null) {
        	Collection<Flash> flashList = (Collection <Flash>)request.getSession().getAttribute(SessionAttribute.FlashList.getName());
            for ( Flash f : flashList) {
            	f.buildDomainXml(root);
            }
            request.getSession().setAttribute(SessionAttribute.FlashList.getName(), null);	
        }
        
        return xmlDoc;
	}
	
	public void addViewOptions(Document xmlDoc){
		this.viewOptions.buildDomainXml(xmlDoc.getRootElement());
	}
	
	private void buildPathXml(Element root) {
		// Add css and image directories
        Element paths = root.addElement("paths");
        Element css = paths.addElement("css");
        css.setText(this.getContextRootURL()+"/css/");
        
        Element images = paths.addElement("images");
        images.setText(this.getContextRootURL()+"/images/");
        
        Element rootUrl = paths.addElement("rootUrl");
        rootUrl.setText(this.getContextRootURL() + "/" + this.appSwitch);
	}
	
	
	public String getContextParameter(String param) {
		String value = this.getRequestParameter(param);
		return value == null ? (String) this.request.getSession().getAttribute(param) : value;
		
	}
	
	public boolean hasReqeustParameter(String param) {
		return this.request.getParameter(param) != null;
	}
	public String getRequestParameter(String param) {
		String value = this.request.getParameter(param);
		return (value == null) ? null : value;
	}
	
	public Object getSessionAttribute(SessionAttribute a) {
		return this.request.getSession().getAttribute(a.getName());
	}
	public void setSessionAttribute(SessionAttribute a, Object o) {
		this.request.getSession().setAttribute(a.getName(), o);
	}
}
